一、生命周期
整个生命周期来说,成对出现的。onCreate和onDestroy是成对的,代表着创建与销毁;onStart和onStop表示Activity对于程序是否可见(后台);onResume和onPause表示Activity对于用户是否可见(前台)。
正常生命周期
1、启动ActivityA:onCreate() -> onStart() -> onResume()
2、按了back键返回:onPause() -> onStop() -> onDestroy()
3、用户按了Home键:onPause() -> onStop()
4、启动ActivityB:A.onPause() -> B.onCreate() -> B.onStart() -> B.onResume() -> A.onStop()
5、ActivityB返回:B.onPause() -> A.onRestart() -> A.onStart() -> A.onResume() -> B.onStop()
-> B.onDestroy()
切换横竖屏幕
targetSdkVersion 25,没有设置android:configChanges:
1、竖屏切横屏:onConfigurationChanged() -> onPause() -> onSaveInstanceState() -> onStop() -> onDestroy() -> onCreate() -> onStart() -> onRestoreInstanceState() -> onResume()
2、横屏切竖屏:onConfigurationChanged() -> onPause() -> onSaveInstanceState() -> onStop() -> onDestroy() -> onCreate() -> onStart() -> onRestoreInstanceState() -> onResume()
本人使用的是模拟器(minSdkVersion 16 / targetSdkVersion 25)测试,无论是否设置Activity的android:configChanges,或者属性值设为orientation或orientation|keyboardHidden,无论是竖屏切横屏还是横屏切竖屏,流程都如上所述,当android:configChanges=”orientation|keyboardHidden|screenSize”时,只会调用onConfigurationChanged()。经过查资料,android:targetSdkVersion这个属性会影响横竖屏切换的生命周期。详见xiaoQLud的博客
异常生命周期
1、系统配置发生改变后,默认情况下Activity会被销毁然后重新创建,生命周期参考横竖屏切换。常用的系统配置只有local、orientation和keyboardHidden。
2、资源内存不足导致低优先级的Activity被杀死,生命周期参考横竖屏切换。
3、运行时发生了异常,程序直接崩溃。例如:
二、数据存储
当Activity在异常情况下被终止,在onStop之前,系统会调用onSaveInstanceState方法,来保存当前Activity状态。当Activity被重新创建后,系统会调用onRestoreInstanceState,并且把Activity销毁时onSaveInstanceState方法所保存的Bundle对象作为参数同时传递给onRestoreInstanceState和onCreate方法。
android提供的一些控件也实现了onSaveInstanceState和onRestoreInstanceState方法,如TextView。
三、启动模式
ActivityManagerService(AMS)内部维护着一个ActivityStack栈,系统会将Activity实例一一放入栈内(先进后出),默认情况下创建一个实例压入栈内。如果多次创建同一个Activity,栈内将压入多个实例。为此,Android提供了启动模式来修改系统的默认行为。目前有四种启动模式:standard、singleTop、singleTask和singleInstance:
standard
标准模式,也是系统默认模式。每次启动一个Activity都会重新创建一个新的实例,不管这个实例是否已经存在。谁启动了这个Activity,那么这个Activity就运行在启动它的那个Activity所在的栈中。ABCBB
singleTop
栈顶复用模式。如果新Activity已经位于任务栈的栈顶,那么只调用它的onNewIntent方法实现复用,而不会创建新的实例。如果新的Activity的实例已存在但不是位于栈顶,仍然重新创建。假设目前栈内情况为ABCD(ABCD为四个Activity,A位于栈底),此时再次启动,如果D的启动模式为singleTop,那么栈内仍然是ABCD;如果D的启动模式为standard,D将被重新创建,栈内情况变为ABCDD。
singleTask
栈内复用模式。在同一个栈内,它是单实例模式。在这种模式下,启动一个Activity A,系统首先会寻找是否存在A想要的任务栈,如果不存在,就重新创建一个任务栈,然后创建A的实例并压入栈内;如果存在所需的任务栈,这时要看A是否在栈中有实例存在,如果有,那么系统就会把A调到栈顶并调用它的onNewIntent方法,不存在就创建并压入栈中。
1、目前任务栈栈S1(ABC),此时Activity D以singleTask模式请求启动,其所需的任务栈为S2,由于S2和D的实例均不存在,所以系统先创建任务栈S2,然后再创建D的实例并将其放入栈S2中。
2、另外一种情况,假设D所需的任务栈为S1,上述S1已存在,所以系统会直接创建D的实例并压入栈S1内。
3、如果D所需的任务栈为S1,其中为ADBC,此时系统将D上面的Activity出栈,把D切换到栈顶并调用onNewIntent方法,最终S1栈内为AD。
singleInstance:
该模式具备singleTask模式的所有特性外,与它的区别就是,这种模式下的Activity会单独占用一个Task栈,具有全局唯一性,即整个系统中就这么一个实例,由于栈内复用的特性,后续的请求均不会创建新的Activity实例,除非这个特殊的任务栈被销毁了。以singleInstance模式启动的Activity在整个系统中是单例的,如果在启动这样的Activiyt时,已经存在了一个实例,那么会把它所在的任务调度到前台,重用这个实例。
以下代码是用于测试启动模式的BaseActivity,具体的Activity继承BaseActivity:
配置形式:
四、意图调用
启动Activity分为两种,显示调用和隐式调用。显示调用通过指定Intent组件名称来实现的,它一般用在知道目标组件名称的前提下,一般是在相同的应用程序内部实现的。隐式调用通过Intent Filter来实现的,它一般用在没有明确指出目标组件名称的前提下,一般是用于在不同应用程序之间。
显示调用
|
|
而Manifest文件描述为:
隐式调用
隐式不明确指定启动哪个Activity,而是在Intent Filter中设置Action、Data、Category,让系统来筛选出合适的Activity。清单文件配置如下:
代码调用:
1、startA()中没有设置category,是因为系统在调用startActivity或者startActivityForResult的时候会默认为Intent加上“android.intent.category.DEFAULT”这个category。所以,为了我们的Activity能接收隐式调用,必须在intent-filter中指定这个category。
2、action区分大小写
3、一个Activity可以有多个intent-filter,一个intent只要能匹配任何一组intent-filter即可启动对应的Activity。